/*
 * DisplayTaskDescription.java
 * 
 * last update: 30.01.2010 by Vlad Badoiu
 * 
 * author:	Alec(panovici@elcom.pub.ro)
 * 
 * Obs:
 */

package engine;
import java.util.*;

/**
 * THe description of the <code>$display, $strobe, 
 * $write && $monitor</code> tasks.
 */

@SuppressWarnings("serial")
class DisplayTaskDescription extends InstructionDescription{
	int id;
	Vector<Object> target;
	int defaultBase, displayType;
	final static int d_write = 0,  d_display = 1,
	d_strobe = 3, d_monitor = 5;

	DisplayTaskDescription(int delayBefore, int line,
			NameSpaceDescription namespace, int db, Vector<Object> v, int type){
		super(delayBefore, line, namespace);
		target = v;
		defaultBase = db;
		displayType = type;
	}

	DisplayTaskDescription(int delayBefore, int line,
			NameSpaceDescription namespace, int db, Vector<Object> v){
		this(delayBefore, line, namespace, db, v, d_display);
	}

	DefaultInstruction instantiate(NameSpace m)throws ParseException{
		String format = "", fx[];
		Vector<Object> r = new Vector<Object>();
		Object o;
		boolean expecting = false;
		for (Enumeration<Object> e = target.elements(); e.hasMoreElements(); ) {
			fx = formatSplit(format);

			if (!"".equals(fx[0])) r.addElement(fx[0]);
			format = fx[1];
			if (!"".equals(fx[2])) {
				r.addElement(fx[2]);
				expecting = !("%m".equals(fx[2]) || "%M".equals(fx[2]));
			}
			if ((!expecting) && (format.length() > 0)) continue;
			o = e.nextElement();
			if (o == null) { r.addElement(null);  continue; }
			if (o instanceof String) {
				if (expecting) {
					try{
						r.addElement(ConstantDescription.
								createNewStringConstantDescription(o.toString()).
								instantiate(m));
					}catch(ParseException ex){
						xConsole.dumpStack(ex);
						throw new ParseException(super.toString() + " error:" + ex);
					}
					expecting = false;
				} else format += o.toString();
			} else {
				try{
					xConsole.debug("DisplayTaskDescription.instantiate: format spec = " + fx[2]);
					if(fx[2].equalsIgnoreCase("%v")){
						//wire strength => a WireSelectionExpression must be supplied
						WireSelection ws;
						try{
							ws = (WireSelection)
							((ExpressionDescription) o).instantiate(m);
						}catch(ClassCastException cex){
							throw new ParseException("a wire or wire conactenation must be supplied for %V format");
						}
						r.addElement((Expression)ws);
					}else
						r.addElement(((ExpressionDescription)o).instantiate(m));
				}catch(ParseException ex){
					xConsole.dumpStack(ex);
					throw new ParseException(super.toString() + " error:" + ex);
				}
				expecting = false;
			}
		}
		do {
			fx = formatSplit(format);
			xConsole.debug("fx[0] = " + fx[0] + " fx[1] = " + fx[1] + " fx[2] = " + fx[2]);
			if (!"".equals(fx[0])) r.addElement(fx[0]);
			if (!"".equals(fx[2])) {
				if (!("%m".equals(fx[2]) || "%M".equals(fx[2])))
					throw new ParseException(super.toString() + " error:format " + fx[2] + " without expression");
				r.addElement(fx[2]);
			}
			format = fx[1];
		} while (!"".equals(format));
		if ((displayType & d_display) != 0) r.addElement("\n");
		switch (displayType) {
		case d_strobe: return new StrobeTask(m, delayBefore, this, defaultBase, r,
				next == null ? null : next.instantiate(m));
		case d_monitor: return new MonitorTask(m, delayBefore, this, defaultBase, r,
				next == null ? null : next.instantiate(m));
		}
		return new DisplayTask(m, delayBefore, this, defaultBase, r,
				next == null ? null : next.instantiate(m));
	}

	/**
	 * imparte in sir in 3 bucati:
	 * "abc %d xyz" => { "abc ", "%d", " xyz" }
	 * r[0] == "abc"
	 * r[1] == "xyz"
	 * r[2] == "%d"
	 */
	String[] formatSplit(String f) throws ParseException{
		xConsole.debug("splitting " + f);
		String[] r = { new String(""), new String(""), new String("") };
		int j;
		char c;
		do {
			j = f.indexOf('%');
			if (j == -1) { r[0] += f;  return r; }
			if (j == f.length()-1) throw new ParseException(super.toString() + " error:missing % format specificator");
			c = f.charAt(j+1);
			if (j > 0) r[0] += f.substring(0, j);
			if (c == '%') {
				r[0] += "%"; //  "%%" in format means a '%' in the output string
				f = f.substring(j+2);
				xConsole.debug("cont...");
				continue;
			}
			if ("hdobcsvmtegfHDOBCSVMTEGF".indexOf(c) == -1)
				throw new ParseException(super.toString() + " error:invalid % format specifier: '" + c + "'");
			r[2] = f.substring(j, j+2);
			r[1] = f.substring(j+2);
			return r;
		} while (true);
	}

	String base() {
		switch (defaultBase) {
		case 10: return "";
		case 2: return "b";
		case 8: return "o";
		case 16: return "h";
		default: return "?";
		}
	}

	public String toString(){
		String s = super.toString() + " $";
		switch (displayType) {
		case d_write: s += "write";  break;
		case d_display: s += "display";  break;
		case d_strobe: s += "strobe";  break;
		case d_monitor: s += "monitor";  break;
		}
		s += base() + "(";
		boolean one = false;
		Object o;
		for (Enumeration e = target.elements(); e.hasMoreElements(); one = true) {
			o = e.nextElement();
			if (o == null) s += (one ? "," : "") + "null";
			else {
				if (o.equals("\n")) o = "\\n";
				s += (one ? "," : "") + (o instanceof String ? "\"" : "") +
				o.toString() + (o instanceof String ? "\"" : "");
			}
		}
		return s + ")";
	}
}

